import telnetlib
import time
import sys
import os
import subprocess
import re
import json


def load_config(config_file="config.json"):
    """
    从JSON配置文件加载参数
    """
    try:
        with open(config_file, 'r', encoding='utf-8') as f:
            config = json.load(f)

        # 验证必要参数是否存在
        required_fields = ['host', 'username', 'password', 'tftp_server', 'filename']
        for field in required_fields:
            if field not in config:
                raise ValueError(f"配置文件中缺少必要字段: {field}")

        print(f"✅ 配置文件加载成功: {config_file}")
        return config

    except FileNotFoundError:
        print(f"❌ 配置文件 {config_file} 不存在")
        # 创建示例配置文件
        create_sample_config(config_file)
        sys.exit(1)
    except json.JSONDecodeError:
        print(f"❌ 配置文件 {config_file} 格式错误")
        sys.exit(1)
    except Exception as e:
        print(f"❌ 加载配置文件时发生错误: {str(e)}")
        sys.exit(1)


def create_sample_config(config_file):
    """
    创建示例配置文件
    """
    sample_config = {
        "host": "192.168.62.1",
        "username": "root",
        "password": "MWSTech2025",
        "tftp_server": "192.168.62.100",
        "filename": "1.bin",
        "download_timeout": 300,
        "reboot_wait_time": 120,
        "ping_count": 4
    }

    try:
        with open(config_file, 'w', encoding='utf-8') as f:
            json.dump(sample_config, f, indent=4, ensure_ascii=False)
        print(f"📝 已创建示例配置文件: {config_file}")
        print("请修改配置文件中的参数后重新运行程序")
    except Exception as e:
        print(f"创建示例配置文件失败: {str(e)}")


def send_telnet_commands(host, username, password, commands):
    try:
        # 连接Telnet服务器
        tn = telnetlib.Telnet(host, timeout=10)

        # 输入用户名
        tn.read_until(b"login: ", timeout=5)
        tn.write(username.encode('ascii') + b"\n")

        # 输入密码
        tn.read_until(b"Password: ", timeout=5)
        tn.write(password.encode('ascii') + b"\n")

        # 等待登录完成
        time.sleep(2)

        # 发送命令
        for cmd in commands:
            tn.write(cmd.encode('ascii') + b"\n")
            time.sleep(1)
            output = tn.read_very_eager().decode('ascii')
            print(f"命令 '{cmd}' 输出:\n{output}")

        # 关闭连接
        tn.write(b"exit\n")
        tn.close()
        return True

    except Exception as e:
        print(f"Telnet操作发生错误: {str(e)}")
        return False


def send_telnet_commands_with_wait(host, username, password, commands, download_timeout=300):
    try:
        # 连接Telnet服务器
        tn = telnetlib.Telnet(host, timeout=10)

        # 输入用户名
        tn.read_until(b"login: ", timeout=5)
        tn.write(username.encode('ascii') + b"\n")

        # 输入密码
        tn.read_until(b"Password: ", timeout=5)
        tn.write(password.encode('ascii') + b"\n")

        # 等待登录完成
        time.sleep(2)

        # 发送前两个命令（cd和tftp）
        for cmd in commands[:2]:
            tn.write(cmd.encode('ascii') + b"\n")
            time.sleep(1)
            output = tn.read_very_eager().decode('ascii')
            print(f"命令 '{cmd}' 输出:\n{output}")

        # 等待tftp下载完成
        print("等待TFTP下载完成...")
        download_complete = wait_for_download_complete(tn, download_timeout)

        if not download_complete:
            print("❌ TFTP下载失败或超时")
            tn.write(b"exit\n")
            tn.close()
            return False

        # 下载完成后执行mtd命令
        print("✅ 文件下载完成，开始执行升级命令...")
        for cmd in commands[2:]:
            tn.write(cmd.encode('ascii') + b"\n")
            time.sleep(2)  # 给mtd命令更多时间
            output = tn.read_very_eager().decode('ascii')
            print(f"命令 '{cmd}' 输出:\n{output}")

        # 关闭连接
        tn.write(b"exit\n")
        tn.close()
        return True

    except Exception as e:
        print(f"Telnet操作发生错误: {str(e)}")
        return False


def wait_for_download_complete(tn, timeout=300):
    """等待tftp下载完成"""
    start_time = time.time()
    last_size = 0
    same_size_count = 0

    print(f"等待下载完成，超时时间: {timeout}秒")

    while time.time() - start_time < timeout:
        try:
            # 发送空命令检查状态
            tn.write(b"\n")
            time.sleep(3)

            # 读取响应
            response = tn.read_very_eager().decode('ascii', errors='ignore')

            # 检查下载完成的关键词
            if any(keyword in response.lower() for keyword in
                   ['received', 'bytes', '100%', 'complete', 'success', 'done']):
                print("✅ 下载完成检测到完成信号")
                return True

            # 检查错误
            if any(error in response.lower() for error in
                   ['error', 'fail', 'timeout', 'not found', 'cannot']):
                print("❌ 下载过程中出现错误")
                print(f"错误信息: {response}")
                return False

            # 尝试获取文件大小信息
            if "bytes" in response:
                print(f"下载进度: {response.strip()}")

            # 检查是否返回命令提示符（表示下载完成）
            if re.search(r'root@.*:.*#', response) or re.search(r'\[.*\].*#', response):
                print("✅ 下载完成，返回命令提示符")
                return True

            print(f"等待下载... ({int(time.time() - start_time)}秒)")
            time.sleep(5)

        except Exception as e:
            print(f"等待下载时发生错误: {str(e)}")
            return False

    print("❌ 下载超时")
    return False


def ping_host(host, count=4):
    try:
        # 根据不同操作系统使用不同的ping参数
        param = "-n" if sys.platform.lower().startswith("win") else "-c"

        # 执行ping命令
        command = ["ping", param, str(count), host]
        response = subprocess.run(command, capture_output=True, text=True, timeout=30)

        if response.returncode == 0:
            print(f"Ping {host} 成功!")
            return True
        else:
            print(f"Ping {host} 失败!")
            return False

    except subprocess.TimeoutExpired:
        print("Ping操作超时")
        return False
    except Exception as e:
        print(f"Ping操作发生错误: {str(e)}")
        return False


def get_software_info(host, username, password):
    """
    获取软件版本信息
    """
    try:
        print("\n" + "=" * 60)
        print("📋 正在获取软件版本信息...")
        print("=" * 60)

        # 连接Telnet服务器
        tn = telnetlib.Telnet(host, timeout=10)

        # 输入用户名
        tn.read_until(b"login: ", timeout=5)
        tn.write(username.encode('ascii') + b"\n")

        # 输入密码
        tn.read_until(b"Password: ", timeout=5)
        tn.write(password.encode('ascii') + b"\n")

        # 等待登录完成
        time.sleep(2)

        # 发送uci show命令
        commands = [
            "uci show /proc/huayi/about.about_software",
        ]

        for cmd in commands:
            print(f"\n执行命令: {cmd}")
            tn.write(cmd.encode('ascii') + b"\n")
            time.sleep(2)
            output = tn.read_very_eager().decode('ascii', errors='ignore')
            print(f"命令输出:\n{output}")

            # 尝试解析版本信息
            parse_version_info(output)

        # 关闭连接
        tn.write(b"exit\n")
        tn.close()
        return True

    except Exception as e:
        print(f"获取软件信息时发生错误: {str(e)}")
        return False


def parse_version_info(output):
    """
    解析版本信息
    """
    print("\n" + "-" * 40)
    print("🔍 解析版本信息:")
    print("-" * 40)

    # 多种可能的版本信息格式
    version_patterns = [
        r'fw_version[=:\s]+["\']?([^"\'\s]+)["\']?',
        r'version[=:\s]+["\']?([^"\'\s]+)["\']?',
        r'software_version[=:\s]+["\']?([^"\'\s]+)["\']?',
        r'about_software\.version[=:\s]+["\']?([^"\'\s]+)["\']?',
        r'about_software\.fw_version[=:\s]+["\']?([^"\'\s]+)["\']?'
    ]

    found_info = False

    for pattern in version_patterns:
        matches = re.findall(pattern, output, re.IGNORECASE)
        for match in matches:
            if match and len(match) > 0:
                print(f"✅ 发现版本信息: {match}")
                found_info = True

    # 如果没有找到特定版本信息，显示所有相关信息
    if not found_info:
        print("📄 完整输出内容:")
        print(output)

    print("-" * 40)


def wait_for_user_exit():
    """
    等待用户主动退出
    """
    print("\n" + "=" * 60)
    print("🏁 程序执行完成")
    print("=" * 60)
    print("窗口将保持打开状态，您可以:")
    print("1. 查看上面的输出信息")
    print("2. 复制需要的数据")
    print("3. 按回车键退出程序")
    print("=" * 60)

    try:
        input("按回车键退出...")
    except:
        pass  # 防止在特殊情况下出现错误

def countdown(seconds):
    """
    简单的倒计时函数，只显示剩余秒数

    参数:
        seconds: 倒计时的总秒数
    """
    print(f"开始 {seconds} 秒倒计时...")

    for i in range(seconds, 0, -1):
        print(f"\r还剩 {i} 秒", end="", flush=True)
        time.sleep(1)

    print("\r时间到！     ")  # 清除最后一行

def main():
    # 从JSON文件加载配置
    config = load_config()

    # 从配置中获取参数
    host = config['host']
    username = config['username']
    password = config['password']
    tftp_server = config['tftp_server']
    filename = config['filename']
    download_timeout = config.get('download_timeout', 600)
    reboot_wait_time = config.get('reboot_wait_time', 120)
    ping_count = config.get('ping_count', 4)

    # 构建升级命令序列
    upgrade_commands = [
        "cd /tmp",
        f"tftp -g -r {filename} {tftp_server}",
        f"mtd -r write {filename} firmware &"
    ]

    print("设备自动升级脚本")
    print("==================")
    print(f"目标设备: {host}")
    print(f"用户名: {username}")
    print(f"TFTP服务器: {tftp_server}")
    print(f"升级文件: {filename}")
    print(f"下载超时: {download_timeout}秒")
    print(f"重启等待: {reboot_wait_time}秒")
    print("注意: 请确保已准备好TFTP服务器和固件文件")
    print("\n按任意键开始升级操作...")

    # 等待用户按键
    input()

    print("开始升级过程...")

    # 发送升级命令（带等待下载功能）
    success = send_telnet_commands_with_wait(
        host, username, password, upgrade_commands, download_timeout
    )

    if success:
        print("升级命令发送完成，等待设备重启...")
        # 等待设备重启（mtd -r write会自动重启）
        print(f"设备正在重启，请等待 {reboot_wait_time} 秒...")
       # time.sleep(reboot_wait_time)
        countdown(reboot_wait_time)
        print("开始检查设备连通性...")
        # 尝试ping设备
        ping_success = ping_host(host, ping_count)

        if ping_success:
            print("✅ 升级成功! 设备可以正常访问。")

            # 升级成功后获取软件信息
            print("\n等待设备完全启动...")
            time.sleep(5)  # 给设备更多时间完全启动

            # 获取软件版本信息
            get_software_info(host, username, password)

        else:
            print("⚠️ 升级后设备无法访问，可能需要进一步检查。")
    else:
        print("❌ 升级过程失败，请检查网络连接和设备状态。")

    # 等待用户主动退出
    wait_for_user_exit()


if __name__ == "__main__":
    main()